<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>安静小树</title>
    <style>
        body {
            font-family: 'Comic Sans MS', 'Arial', sans-serif;
            background: url('https://img.freepik.com/free-vector/cute-animal-background_1308-149614.jpg') repeat;
            background-size: cover;
            margin: 0;
            padding: 20px;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }

        .container {
            text-align: center;
            background: rgba(255, 255, 255, 0.95);
            padding: 30px;
            border-radius: 25px;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
            max-width: 1200px;
            width: 100%;
        }

        h1 {
            color: #ff6f61;
            font-size: 3.5em;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1);
            margin-bottom: 20px;
        }

        .detection-area {
            background: rgba(255, 245, 157, 0.8);
            padding: 20px;
            border-radius: 20px;
            margin-bottom: 20px;
        }

        #start-detection {
            background: linear-gradient(45deg, #ffca28, #ffeb3b);
            color: #d81b60;
            padding: 20px 50px;
            border: none;
            border-radius: 30px;
            cursor: pointer;
            font-size: 2em;
            transition: transform 0.2s;
            margin-bottom: 20px;
        }

        #start-detection:hover {
            transform: scale(1.1);
        }

        #decibel-display {
            font-size: 2em;
            margin: 20px 0;
            color: #d81b60;
            background: #fce4ec;
            padding: 15px;
            border-radius: 15px;
        }

        .settings {
            margin: 20px 0;
            display: flex;
            justify-content: center;
            gap: 25px;
            flex-wrap: wrap;
        }

        .settings label {
            color: #d81b60;
            font-size: 1.5em;
        }

        .settings input {
            padding: 10px;
            border: 3px solid #ffca28;
            border-radius: 10px;
            width: 80px;
            text-align: center;
            font-size: 1.5em;
        }

        .control {
            background: rgba(187, 222, 251, 0.8);
            padding: 20px;
            border-radius: 20px;
            margin-bottom: 20px;
        }

        .control-area {
            display: flex;
            justify-content: center;
            gap: 20px;
            flex-wrap: wrap;
        }

        .control input {
            padding: 10px;
            border: 3px solid #ffca28;
            border-radius: 10px;
            width: 120px;
            text-align: center;
            font-size: 1.5em;
        }

        .control button {
            padding: 15px 30px;
            border: none;
            border-radius: 25px;
            cursor: pointer;
            font-size: 1.5em;
            transition: transform 0.2s;
            color: white;
        }

        .control button:hover {
            transform: scale(1.1);
        }

        #wilt-button {
            background: linear-gradient(45deg, #f06292, #f48fb1);
        }

        #grow-button {
            background: linear-gradient(45deg, #66bb6a, #81c784);
        }

        #reset-button {
            background: linear-gradient(45deg, #42a5f5, #90caf9);
        }

        #reset-all-button {
            background: linear-gradient(45deg, #9575cd, #b39ddb);
        }

        .garden {
            display: grid;
            grid-template-columns: repeat(9, 1fr); /* 固定9列显示 */
            gap: 15px;
            padding: 20px;
            background: rgba(255, 255, 255, 0.7);
            border-radius: 20px;
        }

        .plot {
            background: url('https://img.freepik.com/free-vector/cute-grass-pattern_1308-149615.jpg') center/cover;
            border: 4px solid #ffca28;
            border-radius: 20px;
            height: 160px; /* 增加高度 */
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            align-items: center;
            padding: 10px;
            box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
            transition: transform 0.3s;
        }

        .plot:hover {
            transform: translateY(-5px);
        }

        .student-name {
            font-size: 1.2em;
            color: #d81b60;
            background: rgba(255, 235, 59, 0.8);
            padding: 5px 10px;
            border-radius: 15px;
            width: 100%; /* 固定宽度 */
            box-sizing: border-box;
            /* 移除文本溢出处理，允许名字换行 */
            white-space: normal;
            overflow: visible;
            height: auto; /* 自动高度适应内容 */
            display: flex;
            align-items: center;
            justify-content: center;
            text-align: center;
            min-height: 40px; /* 最小高度确保显示 */
        }

        .tree {
            font-size: 3.5em;
            cursor: pointer;
            transition: transform 0.5s ease;
            margin-top: 10px; /* 增加与名字的间距 */
            flex-grow: 1;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .tree.growing {
            color: #66bb6a;
            animation: grow 2s infinite ease-in-out;
        }

        .tree.wilting {
            color: #f06292;
            animation: wilt 1.5s infinite ease-in-out;
        }

        #audio-indicator {
            width: 300px;
            height: 30px;
            background-color: #f5f5f5;
            border-radius: 15px;
            margin: 10px auto;
            overflow: hidden;
        }

        #audio-level {
            height: 100%;
            width: 0%;
            background: linear-gradient(to right, #66bb6a, #f44336);
            transition: width 0.2s ease;
        }

        @keyframes grow {
            0% { transform: scale(1) rotate(0deg); }
            50% { transform: scale(1.2) rotate(5deg); }
            100% { transform: scale(1) rotate(0deg); }
        }

        @keyframes wilt {
            0% { transform: scale(1) rotate(0deg); }
            50% { transform: scale(0.8) rotate(-5deg); }
            100% { transform: scale(1) rotate(0deg); }
        }

        /* 增加响应式样式 */
        @media screen and (max-width: 1200px) {
            .garden {
                grid-template-columns: repeat(6, 1fr); /* 平板上减少列数 */
            }
        }

        @media screen and (max-width: 768px) {
            .garden {
                grid-template-columns: repeat(3, 1fr); /* 手机上显示3列 */
            }
            
            h1 {
                font-size: 2.5em;
            }
            
            #start-detection {
                font-size: 1.5em;
                padding: 15px 30px;
            }
            
            .settings label {
                font-size: 1.2em;
            }
            
            .settings input {
                font-size: 1.2em;
                width: 60px;
            }
            
            .control button {
                font-size: 1.2em;
                padding: 10px 20px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>小朋友们，安静让小树长大吧！🌱</h1>
        <div class="detection-area">
            <button id="start-detection">开始啦！</button>
            <div id="decibel-display">声音大小：0 分贝</div>
            <div id="audio-indicator">
                <div id="audio-level"></div>
            </div>
            <div class="settings">
                <label>长大分贝：<input type="number" id="grow-threshold" value="30"></label>
                <label>枯萎分贝：<input type="number" id="wilt-threshold" value="60"></label>
                <label>锁定时间：<input type="number" id="lock-duration" value="30" min="1"></label>
                <label>枯萎恢复：<input type="number" id="wilt-recovery" value="20" min="1"></label>
            </div>
        </div>
        <div class="control">
            <div class="control-area">
                <input type="number" id="control-number" placeholder="输入序号 (1-46)">
                <button id="wilt-button">枯萎</button>
                <button id="grow-button">长大</button>
                <button id="reset-button">恢复</button>
                <button id="reset-all-button">全部恢复</button>
            </div>
        </div>
        <div class="garden"></div>
    </div>

    <script>
        document.addEventListener("DOMContentLoaded", () => {
            const totalPlots = 46; // 只保留 46 个小草地
            const garden = document.querySelector(".garden");
            const startButton = document.getElementById("start-detection");
            const decibelDisplay = document.getElementById("decibel-display");
            const audioLevel = document.getElementById("audio-level");
            const growThresholdInput = document.getElementById("grow-threshold");
            const wiltThresholdInput = document.getElementById("wilt-threshold");
            const lockDurationInput = document.getElementById("lock-duration");
            const wiltRecoveryInput = document.getElementById("wilt-recovery");
            const controlNumberInput = document.getElementById("control-number");
            const wiltButton = document.getElementById("wilt-button");
            const growButton = document.getElementById("grow-button");
            const resetButton = document.getElementById("reset-button");
            const resetAllButton = document.getElementById("reset-all-button");

            let decibelValue = 0;
            let audioContext = null;
            let analyser = null;
            let microphone = null;
            let detectionInterval = null;
            let smoothedDecibel = 0; // 添加平滑处理的分贝值

            // 学生名单（编号 1 到 46 对应姓名）
            const studentNames = {
                1: "肖昕宇", 2: "蔡云帆", 3: "雍家毅", 4: "徐婉馨", 5: "王沐慈",
                6: "方子木", 7: "邢怀若", 8: "黄禹霏", 9: "杨兆崑", 10: "周诗哲",
                11: "盛思橦", 12: "李宇辰", 13: "杨昱祺", 14: "饶子萱", 15: "杨智轩",
                16: "杨胡雨萱", 17: "谢星伊", 18: "管宇程", 19: "周善昊", 20: "应翊潇",
                21: "丁睿哲", 22: "毕皓然", 23: "梁子墨", 24: "汪佳骏", 25: "郭姝言",
                26: "张嘉译", 27: "徐梓涵", 28: "段芮浠", 29: "王青时", 30: "陆畅",
                31: "张舒洛", 32: "许可忻", 33: "尹诗杰", 34: "王一航", 35: "付展飞",
                36: "朱乐彤", 37: "叶林烽", 38: "冉纾羽", 39: "杨正予", 40: "叶之言",
                41: "高亚曦", 42: "程梓洋", 43: "杨礼谦", 44: "余沐珊", 45: "张梓艺",
                46: "孙悦轩"
            };

            // 生成 46 个小草地，编号从 1101 到 1146
            for (let i = 0; i < totalPlots; i++) {
                const plot = document.createElement("div");
                plot.classList.add("plot");

                const studentNumber = 1101 + i; // 编号 1101 到 1146
                const studentIndex = i + 1; // 对应学生名单的索引 1 到 46
                const studentName = document.createElement("div");
                studentName.classList.add("student-name");
                studentName.dataset.number = studentNumber; // 存储编号用于查找

                // 显示格式：序号. 姓名
                studentName.textContent = `${studentIndex}. ${studentNames[studentIndex]}`;
                plot.appendChild(studentName);

                const tree = document.createElement("div");
                tree.classList.add("tree");
                tree.textContent = "🌱";
                tree.dataset.state = "normal";
                tree.dataset.timer = 0;
                tree.dataset.locked = "false"; // 新增：是否锁定状态
                tree.dataset.lockTimer = 0; // 新增：锁定状态的计时器
                tree.addEventListener("click", () => {
                    if (tree.dataset.state === "wilting") {
                        tree.dataset.state = "growing";
                        tree.textContent = "🌳";
                        tree.classList.remove("wilting");
                        tree.classList.add("growing");
                        tree.dataset.locked = "true"; // 锁定状态
                        tree.dataset.lockTimer = 0; // 重置锁定计时器
                    } else {
                        tree.dataset.state = "wilting";
                        tree.textContent = "🥀";
                        tree.classList.remove("growing");
                        tree.classList.add("wilting");
                        tree.dataset.locked = "true"; // 锁定状态
                        tree.dataset.lockTimer = 0; // 重置锁定计时器
                    }
                });
                plot.appendChild(tree);

                garden.appendChild(plot);
            }

            // 通过序号控制小树苗状态（输入 1 到 46）
            function controlTree(index, action) {
                if (index >= 1 && index <= 46) {
                    const number = 1100 + index; // 转换为 1101 到 1146
                    const plot = document.querySelector(`.student-name[data-number="${number}"]`).parentElement;
                    const tree = plot.querySelector(".tree");
                    if (tree) {
                        if (action === "wilt") {
                            tree.dataset.state = "wilting";
                            tree.textContent = "🥀";
                            tree.classList.remove("growing");
                            tree.classList.add("wilting");
                            tree.dataset.locked = "true"; // 设置为锁定状态
                            tree.dataset.lockTimer = 0; // 重置锁定计时器
                        } else if (action === "grow") {
                            tree.dataset.state = "growing";
                            tree.textContent = "🌳";
                            tree.classList.remove("wilting");
                            tree.classList.add("growing");
                            tree.dataset.locked = "true"; // 设置为锁定状态
                            tree.dataset.lockTimer = 0; // 重置锁定计时器
                        } else if (action === "reset") {
                            tree.dataset.state = "normal";
                            tree.dataset.timer = 0;
                            tree.textContent = "🌱";
                            tree.classList.remove("growing", "wilting");
                            tree.dataset.locked = "false"; // 解除锁定状态
                            tree.dataset.lockTimer = 0; // 重置锁定计时器
                        }
                    }
                } else {
                    alert("请输入有效的序号（1-46）！");
                }
            }

            // 添加重置所有小树的函数
            function resetAllTrees() {
                document.querySelectorAll(".tree").forEach(tree => {
                    tree.dataset.state = "normal";
                    tree.dataset.timer = 0;
                    tree.textContent = "🌱";
                    tree.classList.remove("growing", "wilting");
                    tree.dataset.locked = "false"; // 解除锁定状态
                    tree.dataset.lockTimer = 0; // 重置锁定计时器
                });
            }

            wiltButton.addEventListener("click", () => {
                const index = parseInt(controlNumberInput.value);
                controlTree(index, "wilt");
            });

            growButton.addEventListener("click", () => {
                const index = parseInt(controlNumberInput.value);
                controlTree(index, "grow");
            });

            resetButton.addEventListener("click", () => {
                const index = parseInt(controlNumberInput.value);
                controlTree(index, "reset");
            });

            resetAllButton.addEventListener("click", resetAllTrees);

            // 计算分贝值，优化为使用平滑分贝值
            function calculateDecibels() {
                const bufferLength = analyser.frequencyBinCount;
                const dataArray = new Uint8Array(bufferLength);
                analyser.getByteTimeDomainData(dataArray);

                let sum = 0;
                for (let i = 0; i < bufferLength; i++) {
                    const sample = (dataArray[i] / 128.0) - 1.0;
                    sum += sample * sample;
                }
                const rms = Math.sqrt(sum / bufferLength);

                const reference = 0.00002;
                if (rms > 0) {
                    decibelValue = 20 * Math.log10(rms / reference);
                    decibelValue = Math.max(0, Math.min(120, decibelValue));
                    
                    // 平滑处理分贝值（加权平均）
                    smoothedDecibel = smoothedDecibel * 0.7 + decibelValue * 0.3;
                } else {
                    decibelValue = 0;
                    smoothedDecibel = smoothedDecibel * 0.9; // 慢慢降低
                }

                // 更新显示
                decibelDisplay.textContent = `声音大小：${Math.round(smoothedDecibel)} 分贝`;
                
                // 更新声音指示器
                const percentage = (smoothedDecibel / 100) * 100;
                audioLevel.style.width = `${Math.min(100, percentage)}%`;
            }

            // 初始化麦克风
            async function startMicrophone() {
                try {
                    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
                    audioContext = new (window.AudioContext || window.webkitAudioContext)();
                    analyser = audioContext.createAnalyser();
                    microphone = audioContext.createMediaStreamSource(stream);

                    analyser.fftSize = 2048;
                    microphone.connect(analyser);

                    detectionInterval = setInterval(() => {
                        calculateDecibels();

                        const growThreshold = parseInt(growThresholdInput.value);
                        const wiltThreshold = parseInt(wiltThresholdInput.value);
                        const lockDuration = parseInt(lockDurationInput.value); // 获取锁定时间
                        const wiltRecovery = parseInt(wiltRecoveryInput.value); // 获取枯萎恢复时间

                        document.querySelectorAll(".tree").forEach(tree => {
                            // 检查锁定状态
                            if (tree.dataset.locked === "true") {
                                let lockTimer = parseInt(tree.dataset.lockTimer);
                                lockTimer++;
                                tree.dataset.lockTimer = lockTimer;
                                
                                // 当锁定时间到期时，解除锁定
                                if (lockTimer >= lockDuration) {
                                    tree.dataset.locked = "false";
                                    tree.dataset.lockTimer = 0;
                                }
                                
                                // 锁定状态下不改变状态，直接返回
                                return;
                            }
                            
                            // 只有非锁定状态的树才受声音影响
                            if (tree.dataset.state === "wilting") {
                                let timer = parseInt(tree.dataset.timer);
                                timer++;
                                tree.dataset.timer = timer;
                                if (timer >= wiltRecovery) { // 使用可配置的枯萎恢复时间
                                    tree.dataset.state = "normal";
                                    tree.dataset.timer = 0;
                                    tree.textContent = "🌱";
                                    tree.classList.remove("wilting");
                                }
                            } else if (smoothedDecibel <= growThreshold) {
                                tree.dataset.state = "growing";
                                tree.textContent = "🌳";
                                tree.classList.add("growing");
                                tree.classList.remove("wilting");
                            } else if (smoothedDecibel >= wiltThreshold) {
                                tree.dataset.state = "wilting";
                                tree.textContent = "🥀";
                                tree.classList.remove("growing");
                                tree.classList.add("wilting");
                            } else {
                                tree.dataset.state = "normal";
                                tree.textContent = "🌱";
                                tree.classList.remove("growing", "wilting");
                            }
                        });
                    }, 1000);
                } catch (err) {
                    console.error("无法访问麦克风：", err);
                    alert("无法打开麦克风哦，请检查设备！");
                }
            }

            // 停止检测
            function stopMicrophone() {
                if (audioContext) {
                    audioContext.close();
                    audioContext = null;
                    analyser = null;
                    microphone = null;
                }
                if (detectionInterval) {
                    clearInterval(detectionInterval);
                    detectionInterval = null;
                }
                decibelDisplay.textContent = `声音大小：0 分贝`;
                audioLevel.style.width = "0%";
            }

            // 开始/停止检测
            startButton.addEventListener("click", () => {
                if (!detectionInterval) {
                    startMicrophone();
                    startButton.textContent = "停止啦！";
                } else {
                    stopMicrophone();
                    startButton.textContent = "开始啦！";
                }
            });
        });
    </script>
</body>
</html>